package com.sdhs.paas.gateway.filter;

import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.UUID;

import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson.JSONObject;
import com.sdhs.paas.authclient.jwt.ServiceAuthUtil;
import com.sdhs.paas.authclient.jwt.UserAuthUtil;
import com.sdhs.paas.authshare.common.msg.BaseResponse;
import com.sdhs.paas.authshare.common.msg.TokenForbiddenResponse;
import com.sdhs.paas.authshare.context.BaseContextHandler;
import com.sdhs.paas.authshare.util.jwt.IJWTInfo;
import com.sdhs.paas.gateway.model.JwtInfoVO;
import com.sdhs.paas.gateway.util.JSONUtil;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Configuration
@Order(1)
public class AdminAuthenticationFilter implements GlobalFilter {
	Logger logger = LoggerFactory.getLogger(getClass());
	
	@Value("${gate.ignore.startWith}")
	private String startWith;

	private static final String GATE_WAY_PREFIX = "/api";
	private static final String LOG_JSON_FORMAT = "{\"X-TraceId\":{},\"sourceIp\":{},\"requestUrl\":{},\"requestUri\":{},\"method\":{},\"executeTime\":{}}";
	private static final String START_TIME = "startTime";
	
	@Autowired
	private UserAuthUtil userAuthUtil;

	@Autowired
	private ServiceAuthUtil serviceAuthUtil;

	@Override
	public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
		ServerHttpRequest request = serverWebExchange.getRequest();
		ServerHttpRequest.Builder mutate = request.mutate();
//		log.info("check token and user permission....");
		LinkedHashSet requiredAttribute = serverWebExchange
				.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
		String requestUri = request.getPath().pathWithinApplication().value();
		//发起请求的IP地址
		String sourceIp = getSourceIp(request);
		//通过网关转发到具体的业务系统的URL
		URI requestUrl = (URI) serverWebExchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
//		if (requiredAttribute != null) {
//			Iterator<URI> iterator = requiredAttribute.iterator();
//			while (iterator.hasNext()) {
//				URI next = iterator.next();
//				if (next.getPath().startsWith(GATE_WAY_PREFIX)) {
//					requestUri = next.getPath().substring(GATE_WAY_PREFIX.length());
//				}
//			}
//		}
		final String method = request.getMethod().toString();
		BaseContextHandler.setToken(null);
		// 不进行拦截的地址
		if (isStartWith(requestUri)) {
			logger.info("不被拦截的请求:"+requestUri);
			ServerHttpRequest build = mutate.header("X-Forwarded-For", sourceIp).build();
			return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
		}
		IJWTInfo user = null;
		ServerHttpRequest newReq = null;
		String uuid = UUID.randomUUID().toString().replace("-", "");
		serverWebExchange.getAttributes().put(START_TIME, System.currentTimeMillis());
		try {
			user = getJWTUser(request, mutate);
			newReq = request.mutate().header("X-Forwarded-For", sourceIp).header("requserid", JSONUtil.obj2json(new JwtInfoVO(user.getUniqueName(),user.getId(),user.getName()))).build();
//			logger.info("TraceId:"+uuid+"-sourceIp:"+sourceIp+"-用户:"+user.getName()+"-发起请求:"+requestUri);
			logger.info("TraceId:{}-sourceIp:{}-用户:{}-发起请求:{}",uuid,sourceIp,user.getName(),requestUri);
		} catch (Exception e) {
			logger.error("用户Token过期异常", e);
			return getVoidMono(serverWebExchange, new TokenForbiddenResponse("User Token Forbidden or Expired!"));
		}
		return gatewayFilterChain.filter(serverWebExchange.mutate().request(newReq).build()).then(Mono.fromRunnable(() -> {
            Long startTime = serverWebExchange.getAttribute(START_TIME);
            if (startTime != null) {
                Long executeTime = (System.currentTimeMillis() - startTime);
                logger.info(LOG_JSON_FORMAT, uuid,sourceIp,requestUrl ,requestUri, method , executeTime );
            }
        }));
	}
	
    /**
     * 网关抛异常
     *
     * @param body
     */
    @NotNull
    private Mono<Void> getVoidMono(ServerWebExchange serverWebExchange, BaseResponse body) {
        serverWebExchange.getResponse().setStatusCode(HttpStatus.OK);
        byte[] bytes = JSONObject.toJSONString(body).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = serverWebExchange.getResponse().bufferFactory().wrap(bytes);
        return serverWebExchange.getResponse().writeWith(Flux.just(buffer));
    }

	
	/**
	 * URI是否以什么打头
	 *
	 * @param requestUri
	 * @return
	 */
	private boolean isStartWith(String requestUri) {
		boolean flag = false;
		for (String s : startWith.split(",")) {
			if (requestUri.startsWith(s)) {
				return true;
			}
		}
		return flag;
	}

	/**
	 * 网关抛异常
	 *
	 * @param body
	 * @param code
	 */
	private Mono<Void> setFailedRequest(ServerWebExchange serverWebExchange, String body, int code) {
		serverWebExchange.getResponse().setStatusCode(HttpStatus.OK);
		return serverWebExchange.getResponse().setComplete();
	}

	/**
	 * 返回session中的用户信息
	 *
	 * @param request
	 * @param ctx
	 * @return
	 */
	private IJWTInfo getJWTUser(ServerHttpRequest request, ServerHttpRequest.Builder ctx) throws Exception {
		List<String> strings = request.getHeaders().get(userAuthUtil.getTokenHeader());
		String authToken = null;
		if (strings != null) {
			authToken = strings.get(0);
		}
		if (StringUtils.isBlank(authToken)) {
			strings = request.getQueryParams().get("token");
			if (strings != null) {
				authToken = strings.get(0);
			}
		}
		ctx.header(userAuthUtil.getTokenHeader(), authToken);
		BaseContextHandler.setToken(authToken);
		return userAuthUtil.getInfoFromToken(authToken);
	}
	
	//获取客户端真实的IP
	private String getSourceIp(ServerHttpRequest request){
		HttpHeaders headers = request.getHeaders();
		InetSocketAddress  inetSocketAddress  = request.getRemoteAddress();
		String sourceIp = inetSocketAddress.getAddress().getHostAddress();
		if(headers != null){
			List<String> xffList = headers.get("X-Forwarded-For");
			if(xffList != null && xffList.size() > 0){
				sourceIp = xffList.get(0);
			}
		}
		return sourceIp;
	}
}
